﻿namespace Arbalest.Web.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Security;
    using Arbalest.Models;
    using DotNetOpenAuth.Messaging;
    using DotNetOpenAuth.OpenId;
    using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
    using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
    using DotNetOpenAuth.OpenId.RelyingParty;

    public class OpenIdController : Controller
    {
        private DataStore dataStore = new DataStore();

        public ActionResult Authenticate()
        {
            string email = string.Empty;
            string fullName = string.Empty;
            string alias = string.Empty;
            IList<string> axResponseAttributeValues = null;

            OpenIdRelyingParty openid = new OpenIdRelyingParty();
            IAuthenticationResponse response = openid.GetResponse();

            if (response != null)
            {
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:

                        FetchResponse axResponse = response.GetExtension<FetchResponse>();
                        if (axResponse != null)
                        {
                            axResponseAttributeValues = axResponse.Attributes[WellKnownAttributes.Contact.Email].Values;
                            email = axResponseAttributeValues.Count > 0 ? axResponseAttributeValues[0] : null;

                            axResponseAttributeValues = axResponse.Attributes[WellKnownAttributes.Name.FullName].Values;
                            fullName = axResponseAttributeValues.Count > 0 ? axResponseAttributeValues[0] : null;

                            axResponseAttributeValues = axResponse.Attributes[WellKnownAttributes.Name.Alias].Values;
                            alias = axResponseAttributeValues.Count > 0 ? axResponseAttributeValues[0] : null;
                        }

                        #region set authentication ticket
                        //Zx: The below line is not exactly wrong but has side-effects when use ASP.NET MVC
                        //It IS a cheap way to set authentication ticket.
                        //FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, false);

                        // Create and set our own authentication ticket 
                        // Reference: http://msdn.microsoft.com/en-us/library/ff649204.aspx

                        
                        KeyValuePair<string, string> customData = new KeyValuePair<string, string>();

                        string userData = response.ClaimedIdentifier.ToString();

                        // Create the authentication ticket
                        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                            1,                              // version (integer)
                            alias,                          // username/screen name
                            DateTime.Now,                   // ticket creation date
                            DateTime.Now.AddMinutes(60),    // ticket expiry date
                            false,                          // ticket persistent
                            userData);                      // other custom data

                        // Encrypt the ticket
                        string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
                        // Create cookie and set the encrypted ticket to the cookie as data.
                        HttpCookie authCookie = new HttpCookie(
                            FormsAuthentication.FormsCookieName, encryptedTicket);
                        authCookie.Expires = DateTime.Now.AddMinutes(60);
                        
                        // Add the cookie to the outgoing cookies collection.
                        Response.Cookies.Add(authCookie);

                        #endregion set authentication ticket

                        return RedirectToAction("Index", "Home");
                        // break;
                    case AuthenticationStatus.Canceled:
                        ModelState.AddModelError("loginIdentifier", "Login was cancelled at the provider");
                        break;
                    case AuthenticationStatus.Failed:
                        ModelState.AddModelError("loginIdentifier", "Login failed using the provided OpenID identifier");
                        break;
                }
            }

            return View(dataStore.GetList<OpenIdProvider>());
        }

        [HttpPost]
        public ActionResult Authenticate(string loginIdentifier)
        {
            if (!Identifier.IsValid(loginIdentifier))
            {
                ModelState.AddModelError("loginIdentifier",
                            "The specified login identifier is invalid");
                return View();
            }
            else
            {
                var openid = new OpenIdRelyingParty();
                IAuthenticationRequest request = 
                    openid.CreateRequest(Identifier.Parse(loginIdentifier));

                // Require some additional data
                FetchRequest axRequest = new FetchRequest();
                axRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Alias));
                axRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email));
                axRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName));
                request.AddExtension(axRequest);

                #region comment out
                // The below code fragment is suppose to be be an alternative syntax
                // But it does not work very well. 
                // Comment out until further investigation can be made.
                //request.AddExtension(new ClaimsRequest
                //{
                //    BirthDate = DemandLevel.NoRequest,
                //    Email = DemandLevel.Require,
                //    FullName = DemandLevel.Require,
                //    Nickname = DemandLevel.NoRequest,
                //    Gender = DemandLevel.NoRequest,
                //    Language = DemandLevel.NoRequest
                //});
                #endregion comment out

                return request.RedirectingResponse.AsActionResult();
            }
        }

        public ActionResult Logout()
        {
            FormsAuthentication.SignOut();

            //redirect to logout success page in page /Authentication/Logout
            return RedirectToAction("Index", "Home");
        }
    }
}


